﻿using System;
using System.Data;
using System.Data.Common;
using System.Collections.Generic;

namespace EnterpriseFramework.DataAccess.Provider
{
    public class DBProvider<T>
    {
        private string factory = string.Empty;
        private string connectionString = string.Empty;
        private DbProviderFactory provider;
        //private DbConnection conn;
        private IDbConnection conn;
        //private DbTransaction tras;
        private IDbTransaction tras;


        public DBProvider(string factory, string connectionString)
        {
            this.factory = factory;
            this.connectionString = connectionString;
            provider = DbProviderFactories.GetFactory(factory);
            conn = provider.CreateConnection();
            conn.ConnectionString = this.connectionString;
        }

        public DBProvider(IDbConnection Conn)
        {
            conn = Conn;
        }


        public DataCollection<T> ExecuteReader(Command ELCmd, AbstractColumn[] columns)
        {
            Type type = typeof(T);
            IDbCommand cmd = null;
            try
            {
                cmd = CreateDbCommand(ELCmd);

                if (conn.State != ConnectionState.Open)
                    conn.Open();

                return new DataCollection<T>(cmd, columns);
            }
            catch (Exception ex)
            {
                //<e> 4
            }
            finally
            {
                if (!IsTransaction && conn.State != ConnectionState.Open)
                    conn.Close();
                if (cmd != null)
                    cmd.Dispose();
            }
            return default(DataCollection<T>);
        }

        public DataCollection<T> ExecuteReader(Command ELCmd, AbstractColumn[] columns, out DataTable datatable)
        {
            Type type = typeof(T);
            List<T> result = new List<T>();
            IDbCommand cmd = null;
            IDataReader reader = null;
            datatable = new DataTable();
            try
            {
                cmd = CreateDbCommand(ELCmd);
                if (conn.State != ConnectionState.Open)
                    conn.Open();
                datatable.Load(cmd.ExecuteReader());
                reader = cmd.ExecuteReader();
            }
            catch (Exception ex)
            {
                //<e> 4
            }
            finally
            {
                if (!IsTransaction && conn.State != ConnectionState.Open)
                    conn.Close();
                if (reader != null && !reader.IsClosed)
                    reader.Close();
                if (cmd != null)
                    cmd.Dispose();
            }
            return default(DataCollection<T>);
        }

        #region - Transaction -

        public void BeginTransaction()
        {
            //if(tras!=null)
            //<e> 5
            tras = conn.BeginTransaction();
            IsTransaction = true;
        }

        public bool IsTransaction
        {
            get;
            set;
        }

        public void Commit()
        {
            if (IsTransaction)
            {
                tras.Commit();
                if (conn.State == ConnectionState.Open)
                    conn.Close();
                tras.Dispose();
                tras = null;
            }
        }

        public void DisposeTrans()
        {
            if (IsTransaction)
            {
                tras.Dispose();
                tras = null;
            }
        }

        public void Rollback()
        {
            if (IsTransaction)
            {
                tras.Rollback();
                DisposeTrans();
            }
        }

        #endregion

        //private List<DbParameter> FillParamerter(List<Parameter> parameters)
        private IDbCommand CreateDbCommand(Command ELCmd)
        {
            //List<DbParameter> sqlparams = new List<DbParameter>();
            IDbCommand cmd = conn.CreateCommand();
            cmd.CommandText = ELCmd.Text;
            cmd.CommandType = ELCmd.commandType;
            cmd.Connection = conn;

            foreach (IParameter param in ELCmd.Parameters)
            {
                //DbParameter sqlparam = provider.CreateParameter();
                IDbDataParameter sqlparam = cmd.CreateParameter();
                sqlparam.DbType = param.DbType;
                sqlparam.ParameterName = param.ParameterName;
                sqlparam.Size = param.Size;
                sqlparam.Value = param.Value;
                sqlparam.Direction = param.Direction;
                cmd.Parameters.Add(sqlparam);
            }
            return cmd;
        }
    }
}
